package challenges;

import game.Challenge;
import gfx.Glyphs;
import gfx.Shapes;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import util.GameClock;
import util.GameVars;
import util.VertexBuffer;
import android.graphics.PointF;

public class NPuzzlePlus extends Challenge {
	private final byte MODE_NORMAL = 0;
	private final byte MODE_COLOUR = 1;

	private Menu menu;
	private Board board;

	private PointF timeLoc = new PointF(1, 5.5f);
	private PointF timerLoc = new PointF(1, 5f);
	private PointF moveLoc = new PointF(9, 5.5f);
	private PointF movesLoc = new PointF(9, 5f);
	
	private long timer;
	
	private int moves;
	
	private byte size, mode;
	
	private boolean roundReady, inMenu;
	
	private FloatBuffer fb;
	private ByteBuffer bb;
	
	public NPuzzlePlus(){
		inMenu = true;
		menu = new Menu();
	}
	
	public void draw(GL10 gl){
		if(inMenu){
			menu.draw(gl);
		}
		else{
			board.draw(gl);
		}
		super.draw(gl);
		if(isPaused){
			Shapes.drawSquare(gl, pauseButtonArray[0].getLoc().x, pauseButtonArray[0].getLoc().y, pauseButtonArray[0].getWidth() * .5f, pauseButtonArray[0].getHeight() * .5f, 1, 1, 1, 1);
			Shapes.drawSquare(gl, pauseButtonArray[1].getLoc().x, pauseButtonArray[1].getLoc().y, pauseButtonArray[1].getWidth() * .5f, pauseButtonArray[1].getHeight() * .5f, 1, 1, 1, 1);
			gl.glColor4f(0, 0, 0, 1);
			if(isWon)
				Glyphs.drawString(gl, "Reshuffle", pauseButtonArray[0].getLoc(), GameVars.TEXT_ALIGNMENT_CENTER);
			else
				Glyphs.drawString(gl, "Resume", pauseButtonArray[0].getLoc(), GameVars.TEXT_ALIGNMENT_CENTER);
			gl.glColor4f(0, 0, 0, 1);
			Glyphs.drawString(gl, "Menu", pauseButtonArray[1].getLoc(), GameVars.TEXT_ALIGNMENT_CENTER);
		}
		if(!inMenu){
			Glyphs.drawString(gl, "Time:", timeLoc, GameVars.TEXT_ALIGNMENT_CENTER);
			Glyphs.drawString(gl, "" + (timer / 60000) + " : " + ((timer /1000) % 60 < 10 ? "0" : "") + ((timer / 1000) % 60) + "." + (timer % 1000) / 100, timerLoc, GameVars.TEXT_ALIGNMENT_CENTER);
			Glyphs.drawString(gl, "Moves:", moveLoc, GameVars.TEXT_ALIGNMENT_CENTER);
			Glyphs.drawString(gl, "" + moves, movesLoc, GameVars.TEXT_ALIGNMENT_CENTER);
		}
	}
	
	public void update(long time){
		if(reloading)
			reset();
		
		super.update(time);
		
		if(inMenu){
			if(menu.startGame()){
				size = menu.getSize();
				mode = menu.getMode();
				board = new Board(size);
				reset();
				inMenu = false;
			}
			else if(menu.quit())
				this.setKill(true);
		}
		else{
			board.update(time);
		}
		if(!inMenu && kill()){
			inMenu = true;
			menu.reset();
			this.setKill(false);
			resume();
			isWon = false;
		}
		
		if(roundReady)
			timer += time;
	}
	
	public boolean handleUp(PointF location) {
		if(super.handleUp(location))
			return false;
		if(inMenu)
			menu.handleUp(location);
		else board.handleUp(location);
		return true;
	}

	public boolean handleDrag(PointF location) {
		if(super.handleDrag(location))
			return false;
		if(inMenu)
			menu.handleDrag(location);
		else board.handleDrag(location);
		return true;
	}

	public boolean handleTouch(PointF location) {
		if(super.handleTouch(location))
			return false;
		if(inMenu)
			menu.handleTouch(location);
		else if(roundReady)
			board.handleTouch(location);
		return true;
	}
	
	public boolean handleBackPress(){
		if(inMenu){
			this.setKill(true);
			return true;
		}
		return super.handleBackPress();
	}
	
	protected FloatBuffer makeFloatBuffer(float[] arr) {
	    bb = ByteBuffer.allocateDirect(arr.length*4);
	    bb.order(ByteOrder.nativeOrder());
	    fb = bb.asFloatBuffer();
	    fb.put(arr);
	    fb.position(0);
	    return fb;
	}
	
	public void reset(){
		timer = 0;
		moves = 0;
		board.reset();
	}
	
	class Board{
		private float[] square = new float[12], colors, cOne, cTwo;
		private long lastShuffle;
		private byte movePossibilities, move, check;
		private Tile[] board;
		private Tile selected;
		private short drawIterator, shuffleIterator, resetIterator, solveIterator, shuffleCount;
		private short maxShuffle, shuffleWait = 25;
		private short holeIndex, lastHole;
		private boolean shuffling;
		private FloatBuffer colorBuffer;
		
		public Board(byte s){
			square[0] = 2;
			square[1] = 0;
			square[2] = 0;
			square[3] = 8;
			square[4] = 0;
			square[5] = 0;
			square[6] = 2;
			square[7] = 6;
			square[8] = 0;
			square[9] = 8;
			square[10] = 6;
			square[11] = 0;
			
			board = new Tile[s * s];
			for(short i = 0; i < board.length - 1; ++i)
				board[i] = new Tile(i);
			holeIndex = (short) (board.length - 1);
		}
		
		public void draw(GL10 gl){
			gl.glPushMatrix();
			gl.glDisable(GL10.GL_TEXTURE_2D);
			gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
			gl.glFrontFace(GL10.GL_CCW);
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, VertexBuffer.getVertexBuffer(square));

		    gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
		    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
		    
			gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, square.length / 3);
			
			gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

			gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
			gl.glEnable(GL10.GL_TEXTURE_2D);
			gl.glPopMatrix();
			for(drawIterator = 0; drawIterator < board.length; ++drawIterator)
				if(board[drawIterator] != null)
					board[drawIterator].draw(gl);
		}
		
		public void update(long time){
			if(shuffleCount >= maxShuffle){
				shuffling = false;
				roundReady = true;
			}
			else if(GameClock.getInstance().getCurrentTime() - lastShuffle > shuffleWait)
				shuffle();
		}

		
		private boolean move(Tile tile){
			if(tile.getIndex() % (short) size > 0 && board[tile.getIndex() - 1] == null)
				return swap(tile.getIndex(), (short) (tile.getIndex() - 1));
			if(tile.getIndex() % (short) size < size - 1 && board[tile.getIndex() + 1] == null)
				return swap(tile.getIndex(), (short) (tile.getIndex() + 1));
			if(tile.getIndex() / (short) size > 0 && board[tile.getIndex() - size] == null)
				return swap(tile.getIndex(), (short) (tile.getIndex() - size));
			if(tile.getIndex() / (short) size < size - 1 && board[tile.getIndex() + size] == null)
				return swap(tile.getIndex(), (short) (tile.getIndex() + size));
			return false;
		}
		public boolean swap(short first, short second){
			holeIndex = (byte) board[first].getIndex();
			board[first].move(second);
			board[second] = board[first];
			board[first] = null;
			return true;
		}
		
		private short checkBounds(PointF loc){
			return (short) (((loc.x - 2) / (6 / (float) size)) + (size) * (short) ((6 - loc.y) / (6 / (float) size)));
		}
		
		public boolean checkBoard(){
			for(solveIterator = 0; solveIterator < board.length - 1; ++solveIterator)
				if(board[solveIterator] == null)
					return false;
				else if(board[solveIterator].getValue() != solveIterator)
					return false;
			return true;
		}
		
		public void shuffle(){
			lastShuffle = GameClock.getInstance().getCurrentTime();
			++shuffleCount;

			movePossibilities = 0;
			if(holeIndex % (short) size > 0 && holeIndex - 1 != lastHole)
				++movePossibilities;
			if(holeIndex % (short) size < size - 1 && holeIndex + 1 != lastHole)
				++movePossibilities;
			if(holeIndex / (short) size > 0 && holeIndex - size != lastHole)
				++movePossibilities;
			if(holeIndex / (short) size < size - 1 && holeIndex + size != lastHole)
				++movePossibilities;
			
			move = (byte) (movePossibilities * Math.random());
			check = 0;
			if(holeIndex % (short) size > 0 && holeIndex - 1 != lastHole){
				if(check == move){
					lastHole = holeIndex;
					swap((short) (board[holeIndex - 1].getIndex()), holeIndex);
					return;
				}
				else ++check;
			}
			if(holeIndex % (short) size < size - 1 && holeIndex + 1 != lastHole){
				if(check == move){
					lastHole = holeIndex;
					swap((short) (board[holeIndex + 1].getIndex()), holeIndex);
					return;
				}
				else ++check;
			}
			if(holeIndex / (short) size > 0 && holeIndex - size != lastHole){
				if(check == move){
					lastHole = holeIndex;
					swap((short) (board[holeIndex - size].getIndex()), holeIndex);
					return;
				}
				else ++check;
			}
			if(holeIndex / (short) size < size - 1 && holeIndex + size != lastHole){
				if(check == move){
					lastHole = holeIndex;
					swap((short) (board[holeIndex + size].getIndex()), holeIndex);
					return;
				}
				else ++check;
			}
		}
		
		public void handleUp(PointF location) {
			if(shuffling)
				for(shuffleIterator = shuffleCount; shuffleIterator < maxShuffle; ++shuffleIterator)
					shuffle();
			if(selected == null)
				return;
			if(board[checkBounds(location)] != null)
				if(board[checkBounds(location)] == selected){
					if(move(selected)){
						++moves;
						if(checkBoard())
							isWon = true;
					}
				}
			selected = null;
		}

		public void handleDrag(PointF location) {
		}

		public void handleTouch(PointF location) {
			if(location.x < 2 || location.x > 8 || location. y < 0 || location.y > 6)
				return;
			selected = board[checkBounds(location)];
		}
		
		public void reset(){
			colors = new float[]{
					0, 0, 0, 1,
					0, 0, 0, 1,
					0, 0, 0, 1,
					0, 0, 0, 1
			};
			colorBuffer = makeFloatBuffer(colors);
			if(mode == MODE_COLOUR){
				cOne = new float[]{
						(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
				};
				cTwo = new float[]{
						(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
				};
			    colors = new float[]{
				    	cOne[0], cOne[1], cOne[2], cOne[3],	// Bottom Left
				    	0, 0, 0, 1,	// Bottom Right
				    	1, 1, 1, 1,	// Top Left
				    	cTwo[0], cTwo[1], cTwo[2], cTwo[3] 	// Top Right
				    };
				colorBuffer = makeFloatBuffer(colors);
				
				float baseR = 1, baseG = 1, baseB = 1;
				float deltaR, deltaG, deltaB, deltaYROne, deltaYGOne, deltaYBOne, deltaYRTwo, deltaYGTwo, deltaYBTwo;
				byte x = 0, y = 0;

				deltaR = -((1 - cTwo[0]) / (float) (size - 1));
				deltaG = -((1 - cTwo[1]) / (float) (size - 1));
				deltaB = -((1 - cTwo[2]) / (float) (size - 1));

				deltaYROne = -((1 - cOne[0]) / (float) (size - 1));
				deltaYGOne = -((1 - cOne[1]) / (float) (size - 1));
				deltaYBOne = -((1 - cOne[2]) / (float) (size - 1));

				deltaYRTwo = -((cTwo[0]) / (float) (size - 1));
				deltaYGTwo = -((cTwo[1]) / (float) (size - 1));
				deltaYBTwo = -((cTwo[2]) / (float) (size - 1));
				
				for(resetIterator = 0; resetIterator < board.length  - 1; ++resetIterator){
					board[resetIterator].setColour(baseR + x * deltaR, baseG + x * deltaG, baseB + x * deltaB, 1);
					
					++x;
					x%=size;
					if(x == 0){
						++y; 
						baseR += deltaYROne;
						baseG += deltaYGOne;
						baseB += deltaYBOne;
						
						deltaR = -(((1 + y * deltaYROne) - (cTwo[0] + y * deltaYRTwo)) / (float) (size - 1));
						deltaG = -(((1 + y * deltaYGOne) - (cTwo[1] + y * deltaYGTwo)) / (float) (size - 1));
						deltaB = -(((1 + y * deltaYBOne) - (cTwo[2] + y * deltaYBTwo)) / (float) (size - 1));
					}
				}
			}
			roundReady = false;
			shuffling = true;
			maxShuffle = (short) (size * size * 5);
			shuffleCount = 0;
		}
	}
	class Tile{
		private short value;
		private short index;
		private PointF drawLoc;
		private float[] colour;
		
		public Tile(short i){
			colour = new float[]{ 1, 1, 1, 1 };
			index = i;
			value = (short) (i);
			drawLoc = new PointF(2 + 6 / (float) size * .5f + (6f/size) * (i % (int) size), 6 - 6 / (float) size * .5f - (6f/(float) size) * (i / (int) size));	
		}
		
		public void draw(GL10 gl){
			if(isPaused && !isWon)
				return;
			switch(mode){
			case MODE_NORMAL:
				Shapes.drawSquare(gl, drawLoc, 6 / (float) size * .5f - .05f, 1, 1, 1, 1);
				gl.glColor4f(0, 0, 0, 1);
				Glyphs.drawString(gl, "" + (value + 1), drawLoc, GameVars.TEXT_ALIGNMENT_CENTER);
				break;
			case MODE_COLOUR:
				Shapes.drawSquare(gl, drawLoc, 6 / (float) size * .5f - .05f, colour[0], colour[1], colour[2], colour[3]);
				break;
			}
		}
		
		public void move(short newIndex){
			index = newIndex;
			drawLoc.set(2 + 6 / (float) size * .5f + (6f/size) * (index % (int) size), 6 - 6 / (float) size * .5f - (6f/(float) size) * (index / (int) size));	
		}
		
		public short getIndex(){ return index; }
		public short getValue(){ return value; }
		public void setColour(float r, float g, float b, float a){ colour = new float[]{r, g, b, a}; }
	}
	
	class Button{
		private float x, y, halfWidth, halfHeight;
		private String str;
		
		public Button(String str, float x, float y, float halfWidth, float halfHeight){
			this.x = x;
			this.y = y;
			this.halfWidth = halfWidth;
			this.halfHeight = halfHeight;
			this.str = str;
		}
		
		public void draw(GL10 gl){
			Shapes.drawSquare(gl, x, y, halfWidth, halfHeight, 1, 1, 1, 1);
			gl.glColor4f(0, 0, 0, 1);
			Glyphs.drawString(gl, str, x, y, GameVars.TEXT_ALIGNMENT_CENTER);
		}
		
		public boolean checkBounds(PointF location){
			if(Math.abs(location.x - x) < halfWidth && Math.abs(location.y - y) < halfHeight)
				return true;
			return false;
		}
	}
	
	class Menu{
		private TwoDSlider sizeSlider, modeSlider;
		private Button quit, play, selectedButton;
		private short drawIterator;
		private boolean isDone, kill;
		private float[] sizeColour, modeColour, cOne, cTwo, sizeSquare = new float[12], modeSquare = new float[12];
		FloatBuffer sizeColorBuffer, modeColorBuffer;
		
		public Menu(){
			float deltaR, deltaG, deltaB;
			
			play = new Button("Play", 8, 1, 1, .5f);
			quit = new Button("Quit", 2, 1, 1, .5f);
			sizeSlider = new TwoDSlider((byte) 8, 5, 3, .5f);
			modeSlider = new TwoDSlider((byte) 2, 5, 1, .5f);

			cOne = new float[]{
					(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
			};
			cTwo = new float[]{
					(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
			};
		    sizeColour = new float[]{
			    	cOne[0], cOne[1], cOne[2], cOne[3],	// Bottom Left
			    	0, 0, 0, 1,	// Bottom Right
			    	1, 1, 1, 1,	// Top Left
			    	cTwo[0], cTwo[1], cTwo[2], cTwo[3] 	// Top Right
			    };

			deltaR = -(cOne[0] - cTwo[0]) / (float) (sizeSlider.getLength() - 2);
			deltaG = -(cOne[1] - cTwo[1]) / (float) (sizeSlider.getLength() - 2);
			deltaB = -(cOne[2] - cTwo[2]) / (float) (sizeSlider.getLength() - 2);
			
			for(byte i = 1; i < sizeSlider.getLength(); ++i){
				sizeSlider.get(i).setColour(cOne[0] + deltaR * (i - 1), cOne[1] + deltaG * (i - 1), cOne[2] + deltaB * (i - 1), 1);
			}

			cOne = new float[]{
					(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
			};
			cTwo = new float[]{
					(float) Math.random(), (float) Math.random(), (float) Math.random(), 1
			};
			modeColour = new float[]{
			    	cOne[0], cOne[1], cOne[2], cOne[3],	// Bottom Left
			    	0, 0, 0, 1,	// Bottom Right
			    	1, 1, 1, 1,	// Top Left
			    	cTwo[0], cTwo[1], cTwo[2], cTwo[3] 	// Top Right
			    };

			sizeColorBuffer = makeFloatBuffer(sizeColour);
			modeColorBuffer = makeFloatBuffer(modeColour);

			deltaR = (cOne[0] - cTwo[0]) / (float) (size - 2);
			deltaG = (cOne[1] - cTwo[1]) / (float) (size - 2);
			deltaB = (cOne[2] - cTwo[2]) / (float) (size - 2);
			
			for(byte i = 1; i < modeSlider.getLength(); ++i){
				modeSlider.get(i).setColour(cOne[0] + deltaR * (i - 1), cOne[1] + deltaG * (i - 1), cOne[2] + deltaB * (i - 1), 1);
			}
			
			sizeSquare[0] = 1;
			sizeSquare[1] = 2.5f;
			sizeSquare[2] = 0;
			sizeSquare[3] = 9;
			sizeSquare[4] = 2.5f;
			sizeSquare[5] = 0;
			sizeSquare[6] = 1;
			sizeSquare[7] = 3.5f;
			sizeSquare[8] = 0;
			sizeSquare[9] = 9;
			sizeSquare[10] = 3.5f;
			sizeSquare[11] = 0;
			
			modeSquare[0] = 4;
			modeSquare[1] = .5f;
			modeSquare[2] = 0;
			modeSquare[3] = 6;
			modeSquare[4] = .5f;
			modeSquare[5] = 0;
			modeSquare[6] = 4;
			modeSquare[7] = 1.5f;
			modeSquare[8] = 0;
			modeSquare[9] = 6;
			modeSquare[10] = 1.5f;
			modeSquare[11] = 0;
		}
		
		public void draw(GL10 gl){
			play.draw(gl);
			quit.draw(gl);
			 
			gl.glPushMatrix();
			gl.glTranslatef(5, 5, 0);
			gl.glScalef(2, 2, 1);
			
			Glyphs.drawString(gl, "N-Puzzle +", null, GameVars.TEXT_ALIGNMENT_CENTER);
			
			gl.glPopMatrix();
			
			Glyphs.drawString(gl, "Size:", 5, 4f, GameVars.TEXT_ALIGNMENT_CENTER);
			Glyphs.drawString(gl, "Mode:", 5, 2f, GameVars.TEXT_ALIGNMENT_CENTER);
			
			if(modeSlider.getSelectedValue() == 0){
				Shapes.drawSquare(gl, 5, 3, 4, .5f, 1, 1, 1, 1);
				Shapes.drawSquare(gl, 5, 1, 1, .5f, 1, 1, 1, 1);
			}
			else{
				gl.glPushMatrix();
				gl.glDisable(GL10.GL_TEXTURE_2D);
				gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
				gl.glFrontFace(GL10.GL_CCW);
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, VertexBuffer.getVertexBuffer(sizeSquare));

			    gl.glColorPointer(4, GL10.GL_FLOAT, 0, sizeColorBuffer);
			    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
			    
				gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, sizeSquare.length / 3);
				
				gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

				gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
				gl.glEnable(GL10.GL_TEXTURE_2D);
				gl.glPopMatrix();
				
				gl.glPushMatrix();
				gl.glDisable(GL10.GL_TEXTURE_2D);
				gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
				gl.glFrontFace(GL10.GL_CCW);
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, VertexBuffer.getVertexBuffer(modeSquare));

			    gl.glColorPointer(4, GL10.GL_FLOAT, 0, modeColorBuffer);
			    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
			    
				gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, modeSquare.length / 3);
				
				gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

				gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
				gl.glEnable(GL10.GL_TEXTURE_2D);
				gl.glPopMatrix();
			}

			for(drawIterator = 0; drawIterator < sizeSlider.getLength(); ++drawIterator){
				gl.glColor4f(0, 0, 0, 1);
				Glyphs.drawString(gl, "" + (drawIterator + 3), 5 - sizeSlider.getLength() * .5f + .5f * 2 * drawIterator + .5f, 3, GameVars.TEXT_ALIGNMENT_CENTER);
			}
			sizeSlider.draw(gl);
			modeSlider.draw(gl);
		}
		
		public void handleUp(PointF location) {
			sizeSlider.handleUp(location);
			modeSlider.handleUp(location);
			
			if(selectedButton == play && play.checkBounds(location))
				isDone = true;
			else if(selectedButton == quit && quit.checkBounds(location))
				kill = true;
			selectedButton = null;
		}

		public void handleDrag(PointF location) {
		}

		public void handleTouch(PointF location) {
			if(sizeSlider.checkBounds(location))
				sizeSlider.handleTouch(location);
			else if(modeSlider.checkBounds(location))
				modeSlider.handleTouch(location);
			else if(play.checkBounds(location))
				selectedButton = play;
			else if(quit.checkBounds(location))
				selectedButton = quit;
		}
		
		public boolean startGame(){
			return isDone;
		}
		
		public boolean quit(){
			return kill;
		}
		
		public byte getSize(){ return (byte) (sizeSlider.getSelectedValue() + 3); }
		public byte getMode(){ return modeSlider.getSelectedValue(); }
		
		public void reset(){
			isDone = false;
			kill = false;
		}
		
		class TwoDSlider{
			float x, y, tileHalfWidth;
			private Tile selected, touched;
			private Tile[] tiles;
			private short drawIterator;
			
			public TwoDSlider(byte length, float x, float y, float tileHalfWidth){
				tiles = new Tile[length];
				for(int i = 0; i < tiles.length; ++i)
					tiles[i] = new Tile((byte) i, x - length * tileHalfWidth + tileHalfWidth * 2 * i + tileHalfWidth, y, tileHalfWidth, true);
				tiles[0].setDrawn(false);
				this.x = x;
				this.y = y;
				this.tileHalfWidth = tileHalfWidth;
				selected = tiles[0];
			}
			
			public void draw(GL10 gl){
				for(drawIterator = 0; drawIterator < tiles.length; ++drawIterator){
					tiles[drawIterator].draw(gl);
				}
			}
			
			public void handleUp(PointF location){
				if(touched == null)
					return;
				if(touched == tiles[(int) (location.x - (x - tiles.length * tileHalfWidth))]){
					if(touched.getValue() - 1 == getSelectedValue()){
						selected.setColour(touched.getR(), touched.getG(), touched.getB(), 1);
						selected.setDrawn(true);
						selected = touched;
						touched.setDrawn(false);
					}
					else if(touched.getValue() + 1 == getSelectedValue()){
						selected.setColour(touched.getR(), touched.getG(), touched.getB(), 1);
						selected.setDrawn(true);
						selected = touched;
						touched.setDrawn(false);
					}
				}
				touched = null;
			}
			
			public void handleTouch(PointF location){
				touched = tiles[(int) (location.x - (x - tiles.length * tileHalfWidth))];
			}
			
			public boolean checkBounds(PointF loc){
				if(Math.abs(loc.x - x) < tiles.length * tileHalfWidth && Math.abs(loc.y - y) < tileHalfWidth)
					return true;
				return false;
			}
			
			public byte getSelectedValue(){ return selected.getValue(); }
			public byte getLength(){ return (byte) tiles.length; }
			public Tile get(byte index){ return tiles[index]; }
			
			class Tile{
				private byte value;
				private boolean drawn;
				private float halfWidth, x, y;
				private float r, g, b, a;
				
				public Tile(byte value, float x, float y, float halfWidth, boolean isDrawn){
					this.value = value;
					this.x = x;
					this.y = y;
					this.halfWidth = halfWidth;
					drawn = isDrawn;
				}
				
				public void draw(GL10 gl){
					if(drawn){
						if(modeSlider.getSelectedValue() == 0)
							Shapes.drawSquare(gl, x, y, halfWidth - .05f, halfWidth - .05f, 0, 0, 0, 1);
						else Shapes.drawSquare(gl, x, y, halfWidth - .05f, halfWidth - .05f, r, g, b, 1);
					}
				}
				
				public byte getValue(){ return value; }
				public void setDrawn(boolean d){ drawn = d; }
				public void setColour(float nR, float nG, float nB, float nA){
					r = nR;
					b = nB;
					g = nG;
					a = nA;
				}
				public float getR(){ return r; }
				public float getG(){ return g; }
				public float getB(){ return b; }
				public float getA(){ return a; }
			}
		}
	}
}